package rule

import (
	"gf-xb-api/cwt/consts"
	"gf-xb-api/cwt/filter/model"
	impl2 "gf-xb-api/cwt/filter/parser/rule/impl"
	"gf-xb-api/utility/xstr"
	"reflect"
	"strconv"
	"strings"

	"github.com/gogf/gf/v2/database/gdb"
)

type IRuleParser[T any] interface {
	Parse(op string, fieldName string, rule *model.FilterRule[T], m *gdb.Model) *gdb.WhereBuilder
}

func GetRuleParser[T any](key any) (IRuleParser[T], error) {

	keyStr, err := xstr.GetKeyStr(key)
	if err != nil {
		return nil, err
	}

	var ruleParser IRuleParser[T]
	switch *keyStr {
	case strconv.Itoa(model.Equal), model.EqualOperator:
		ruleParser = &impl2.EqualRuleParser[T]{}

	case strconv.Itoa(model.NotEqual), model.NotEqualOperator:
		ruleParser = &impl2.NotEqualRuleParser[T]{}

	case strconv.Itoa(model.Less), model.LessOperator:
		ruleParser = &impl2.LessThanRuleParser[T]{}

	case strconv.Itoa(model.LessOrEqual), model.LessOrEqualOperator:
		ruleParser = &impl2.LessOrEqualThanRuleParser[T]{}

	case strconv.Itoa(model.Greater), model.GreaterOperator:
		ruleParser = &impl2.GreaterThanRuleParser[T]{}

	case strconv.Itoa(model.GreaterOrEqual), model.GreaterOrEqualOperator:
		ruleParser = &impl2.GreaterOrEqualThanRuleParser[T]{}

	case strconv.Itoa(model.StartsWith), model.StartsWithOperator:
		ruleParser = &impl2.StartsWithRuleParser[T]{}

	case strconv.Itoa(model.EndsWith), model.EndsWithOperator:
		ruleParser = &impl2.EndsWithRuleParser[T]{}

	case strconv.Itoa(model.Contains), model.ContainsOperator:
		ruleParser = &impl2.ContainsRuleParser[T]{}

	case strconv.Itoa(model.NotContains), model.NotContainsOperator:
		ruleParser = &impl2.NotContainsRuleParser[T]{}

	case strconv.Itoa(model.StartsWithOrReverseStartsWith), model.StartsWithOrReverseStartsWithOperator:
		ruleParser = &impl2.StartsWithOrReverseStartsWith[T]{}
	case strconv.Itoa(model.In), model.InOperator:
		ruleParser = &impl2.InRuleParser[T]{}

	case strconv.Itoa(model.IsNull), model.NullOperator:
		ruleParser = &impl2.IsNullRuleParser[T]{}

	case strconv.Itoa(model.IsNotNull), model.NotNullOperator:
		ruleParser = &impl2.IsNotNullRuleParser[T]{}

	case strconv.Itoa(model.Between), model.BetweenOperator:
		ruleParser = &impl2.BetweenRuleParser[T]{}
	}

	return ruleParser, nil
}

// GetDbFieldName ... 获得数据库字段名
func GetDbFieldName[T any](fieldName string) string {

	var t T
	tp := reflect.TypeOf(t)

	field, _ := tp.FieldByNameFunc(func(s string) bool {
		return strings.ToLower(s) == strings.ToLower(fieldName)
	})

	dbFieldName := field.Tag.Get(consts.DB_FIELD_NAME) // alias
	if !xstr.IsBlank(dbFieldName) {
		fieldName = dbFieldName
	}

	return fieldName
}
